home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / msdos / viewers / hv12 / src / dither.c next >
C/C++ Source or Header  |  1992-07-17  |  7KB  |  245 lines

  1. /*
  2.     NAME
  3.        dither - routines to do Floyd-Steinberg dithering
  4.  
  5.    DESCRIPTION
  6.       The assumption is that you have input values in the range
  7.       minIn..maxIn that you want to reduce to the range
  8.       minOut..maxOut.  (For color images, you would dither each color
  9.       component separately.)
  10.  
  11.        Dither a serpentine version of Floyd-Steinberg dithering.  The
  12.       skeleton code to use these routines is:
  13.  
  14.           DitherInit();
  15.          onOddRow = FALSE;
  16.          for (each row) {
  17.              Dither(row, onOddRow);
  18.             onOddRow = !onOddRow;
  19.          }
  20.          DitherTerm();
  21. */
  22.  
  23. #include "jinclude.h"
  24. #include "jmemsys.h"
  25. #include "viewer.h"
  26. #include "hicolor.h"
  27. #include "dither.h"
  28.  
  29.  
  30. #define DInflateBase 15
  31.  
  32. extern BYTE ColorLUT256[];
  33. /*
  34.     NAME
  35.        Dither - apply Floyd-Steinberg dithering to one row
  36.  
  37.    DESCRIPTION
  38.        Adapted from the JPEG source code.
  39.  
  40.       Note that it is acceptable to have pIn == pOut, i.e., to do the
  41.       dithering in place.
  42. */
  43.  
  44. void 
  45. Dither (
  46.      DCtrlType * pCtrl,    /* structure with control parameters */
  47.      int *pIn,      /* input values */
  48.      int *pOut,     /* output values */
  49.      int onOddRow        /* TRUE => current row is odd-numbered */
  50. )
  51. {
  52.   int col;            /* column counter */
  53.   int dir;            /* direction flag */
  54.   int error;            /* value of current error */
  55.   int *nextRowErr;        /* pointer to error buffer for next row */
  56.   int *thisRowErr;        /* pointer to error buffer for this row */
  57.   ulong scale = pCtrl->scale;
  58.   ulong invscale = pCtrl->invscale;
  59.   int val;            /* holds dithered value */
  60.   int width = pCtrl->numCols;
  61.  
  62.   if (onOddRow)
  63.     {                /* work right to left in this row */
  64.       pIn += width - 1;
  65.       pOut += width - 1;
  66.       dir = -1;
  67.       thisRowErr = pCtrl->oddRowErrs + 1;
  68.       nextRowErr = pCtrl->evenRowErrs + width;
  69.     }
  70.   else
  71.     {                /* work left to right in this row */
  72.       dir = 1;
  73.       thisRowErr = pCtrl->evenRowErrs + 1;
  74.       nextRowErr = pCtrl->oddRowErrs + width;
  75.     }
  76.   nextRowErr[0] = 0;        /* need only initialize this one entry */
  77.   for (col = width; col > 0; col--)
  78.     {
  79.  
  80.       /* get current value and adjust for accumulated error */
  81.       val = ((*pIn) << 4) + thisRowErr[0];    /* errors are in units of 1/16 */
  82.       if (val < 0)
  83.     val = 0;
  84.       else
  85.     {
  86. #ifdef OLD_CODE
  87.       val += 8;     /* for rounding */
  88. #endif
  89.       val >>= 4;
  90.       if (val > pCtrl->maxIn)
  91.         val = pCtrl->maxIn;
  92.     }
  93.  
  94.       /* reduce input value to dithered value */
  95.       *pOut = (int) (pCtrl->minOut +
  96.              ((scale * (val - pCtrl->minIn) + (1L << (DInflateBase - 1))) >> DInflateBase));
  97.  
  98.       /* calculate error (in units of 1/16 value) in dithered value */
  99.       error = -(int) (pCtrl->minIn + (((*pOut - pCtrl->minOut) * invscale
  100.               + (1L << (DInflateBase - 1))) >> DInflateBase) - val);
  101.  
  102.       /* store the error */
  103.       val = 2 * error;
  104.       nextRowErr[-1] = error;    /* not +=, since not initialized yet */
  105.       error += val;        /* form error * 3 */
  106.       nextRowErr[1] += error;
  107.       error += val;        /* form error * 5 */
  108.       nextRowErr[0] += error;
  109.       error += val;        /* form error * 7 */
  110.       thisRowErr[1] += error;
  111.       pIn += dir;
  112.       pOut += dir;
  113.       thisRowErr += 1;
  114.       nextRowErr -= 1;
  115.     }
  116. }
  117.  
  118. void 
  119. DitherChar (
  120.      DCtrlType * pCtrl,    /* structure with control parameters */
  121.      JSAMPLE *pIn,      /* input values */
  122.      JSAMPLE *pOut,     /* output values */
  123.      int onOddRow        /* TRUE => current row is odd-numbered */
  124. )
  125. {
  126.   int col;            /* column counter */
  127.   int dir;            /* direction flag */
  128.   int error;            /* value of current error */
  129.   int *nextRowErr;        /* pointer to error buffer for next row */
  130.   int *thisRowErr;        /* pointer to error buffer for this row */
  131.   ulong scale = pCtrl->scale;
  132.   ulong invscale = pCtrl->invscale;
  133.   int val;            /* holds dithered value */
  134.   int width = pCtrl->numCols;
  135.  
  136.   if (onOddRow)
  137.     {                /* work right to left in this row */
  138.       pIn += width - 1;
  139.       pOut += width - 1;
  140.       dir = -1;
  141.       thisRowErr = pCtrl->oddRowErrs + 1;
  142.       nextRowErr = pCtrl->evenRowErrs + width;
  143.     }
  144.   else
  145.     {                /* work left to right in this row */
  146.       dir = 1;
  147.       thisRowErr = pCtrl->evenRowErrs + 1;
  148.       nextRowErr = pCtrl->oddRowErrs + width;
  149.     }
  150.   nextRowErr[0] = 0;        /* need only initialize this one entry */
  151.   for (col = width; col > 0; col--)
  152.     {
  153.  
  154.       /* get current value and adjust for accumulated error */
  155.       val = ((ColorLUT256[GETJSAMPLE(*pIn)]) << 4) + thisRowErr[0];    /* errors are in units of 1/16 */
  156.       if (val < 0)
  157.     val = 0;
  158.       else
  159.     {
  160. #ifdef OLD_CODE
  161.       val += 8;     /* for rounding */
  162. #endif
  163.       val >>= 4;
  164.       if (val > pCtrl->maxIn)
  165.         val = pCtrl->maxIn;
  166.     }
  167.  
  168.       /* reduce input value to dithered value */
  169.       *pOut = (JSAMPLE) (pCtrl->minOut +
  170.              ((scale * (val - pCtrl->minIn) + (1L << (DInflateBase - 1))) >> DInflateBase));
  171.  
  172.       /* calculate error (in units of 1/16 value) in dithered value */
  173.       error = -(int) (pCtrl->minIn + (((*pOut - pCtrl->minOut) * invscale
  174.               + (1L << (DInflateBase - 1))) >> DInflateBase) - val);
  175.  
  176.       /* store the error */
  177.       val = 2 * error;
  178.       nextRowErr[-1] = error;    /* not +=, since not initialized yet */
  179.       error += val;        /* form error * 3 */
  180.       nextRowErr[1] += error;
  181.       error += val;        /* form error * 5 */
  182.       nextRowErr[0] += error;
  183.       error += val;        /* form error * 7 */
  184.       thisRowErr[1] += error;
  185.       pIn += dir;
  186.       pOut += dir;
  187.       thisRowErr += 1;
  188.       nextRowErr -= 1;
  189.     }
  190. }
  191.  
  192. /*
  193.     NAME
  194.        DitherInit - initialize dither buffers and control parameters
  195.  
  196.    RETURN VALUES
  197.        0        if all OK
  198.       1        on error (probably insufficient memory)
  199. */
  200.  
  201. int 
  202. DitherInit (
  203.          BYTE minIn,    /* minimum input value */
  204.          BYTE maxIn,    /* maximum input value */
  205.          BYTE minOut,    /* minimum output value */
  206.          BYTE maxOut,    /* maximum output value */
  207.          int numCols,    /* number of columns in each row */
  208.          DCtrlType * pCtrl    /* structure with control parameters */
  209. )
  210. {
  211.   pCtrl->minIn = minIn;
  212.   pCtrl->maxIn = maxIn;
  213.   pCtrl->minOut = minOut;
  214.   pCtrl->maxOut = maxOut;
  215.   pCtrl->numCols = numCols;
  216.   pCtrl->scale = ((maxOut - minOut) << DInflateBase) / (maxIn - minIn);
  217.   pCtrl->invscale = ((maxIn - minIn) << DInflateBase) / (maxOut - minOut);
  218.   pCtrl->oddRowErrs = (int *) jget_small ((numCols + 2) * sizeof (int));
  219.   if (pCtrl->oddRowErrs == NULL)
  220.     return 1;
  221.   memset (pCtrl->oddRowErrs, 0, (numCols + 2) * sizeof (int));
  222.   pCtrl->evenRowErrs = (int *) jget_small ((numCols + 2) * sizeof (int));
  223.   if (pCtrl->evenRowErrs == NULL)
  224.     return 1;
  225.   memset (pCtrl->evenRowErrs, 0, (numCols + 2) * sizeof (int));
  226.   return 0;
  227. }
  228.  
  229. /*
  230.     NAME
  231.        DitherTerm - clean up after dither operation
  232.  
  233.    DESCRIPTION
  234.        Frees up memory used for error buffers.
  235. */
  236.  
  237. void 
  238. DitherTerm (
  239.          DCtrlType * pCtrl    /* structure with control parameters */
  240. )
  241. {
  242.   jfree_small (pCtrl->oddRowErrs);
  243.   jfree_small (pCtrl->evenRowErrs);
  244. }
  245.